#ifndef COMMOM_GLSL
#define COMMOM_GLSL

#include "Random.glsl"

#define M_PI 3.14159265359
#define EPSILON 0.0001f

#define LIGHT_TYPE_DIRECTIONAL 0
#define LIGHT_TYPE_POINT 1
#define LIGHT_TYPE_SPOT 2

#define MIRROR_REFLECTIONS_ROUGHNESS_THRESHOLD 0.05f
#define DDGI_REFLECTIONS_ROUGHNESS_THRESHOLD 0.75f

struct Vertex
{
	vec3 position;
	vec3 normal;
	vec3 tangent;
	vec2 uv;
};

struct Material
{
    vec4 albedo;
    vec4 emissive;
    vec4 roughnessMetallic;
};

struct ObjectDesc
{
	uint64_t vertexAddress;
	uint64_t indexAddress;
};

struct Light
{
    vec4 data0;
    vec4 data1;
    vec4 data2;
    vec4 data3;
};

vec3 GetLightDirection(in Light light)
{
    return light.data0.xyz;
}

vec3 GetLightColor(in Light light)
{
    return light.data2.xyz;
}

float GetLightIntensity(in Light light)
{
    return light.data0.w;
}

float GetLightRadius(in Light light)
{
    return light.data1.w;
}

vec3 GetLightPosition(in Light light)
{
    return light.data1.xyz;
}

int GetLightType(in Light light)
{
    return int(light.data3.x);
}

float GetLightCosThetaOuter(in Light light)
{
    return light.data3.y;
}

float GetLightCosThetaInner(in Light light)
{
    return light.data3.z;
}

float Luminance(vec3 rgb)
{
    return max(dot(rgb, vec3(0.299, 0.587, 0.114)), 0.0001);
}


vec3 OctohedralToDirection(vec2 e)
{
    vec3 v = vec3(e, 1.0 - abs(e.x) - abs(e.y));
    if (v.z < 0.0)
        v.xy = (1.0 - abs(v.yx)) * (step(0.0, v.xy) * 2.0 - vec2(1.0));
    return normalize(v);
}


float GaussianWeight(float offset, float deviation)
{
    float weight = 1.0 / sqrt(2.0 * M_PI * deviation * deviation);
    weight *= exp(-(offset * offset) / (2.0 * deviation * deviation));
    return weight;
}


vec3 WorldPositionFromDepth(vec2 texCoords, float ndcDepth, mat4 projViewInverse)
{
    // Take texture coordinate and remap to [-1.0, 1.0] range.
    vec2 screenPos = texCoords * 2.0 - 1.0;

    // // Create NDC position.
    vec4 ndcPos = vec4(screenPos, ndcDepth, 1.0);

    // Transform back into world position.
    vec4 worldPos = projViewInverse * ndcPos;

    // Undo projection.
    worldPos = worldPos / worldPos.w;

    return worldPos.xyz;
}


float LinearEyeDepth(float z, vec4 zBufferParams)
{
    return 1.0 / (zBufferParams.z * z + zBufferParams.w);
}


#endif